home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the 3D Game Programming Gurus / gurus.iso / DirectX / dx9sdkcp.exe / SDK (C++) / Bin / DXUtils / Visual Studio 6.0 Wizards / Source Code / Template / netconnect.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2002-11-12  |  78.5 KB  |  2,136 lines

  1. //-----------------------------------------------------------------------------
  2. // File: NetConnect.cpp
  3. //
  4. // Desc: This is a class that given a IDirectPlay8Peer, then DoConnectWizard()
  5. //       will enumerate service providers, enumerate hosts, and allow the
  6. //       user to either join or host a session.  The class uses
  7. //       dialog boxes and GDI for the interactive UI.  Most games will
  8. //       want to change the graphics to use Direct3D or another graphics
  9. //       layer, but this simplistic sample uses dialog boxes.  Feel 
  10. //       free to use this class as a starting point for adding extra 
  11. //       functionality.
  12. //-----------------------------------------------------------------------------
  13. #ifndef STRICT
  14. #define STRICT
  15. #endif // !STRICT
  16. $$IF(DLG)
  17. #include "stdafx.h"
  18. $$ENDIF
  19. #include <windows.h>
  20. #include <basetsd.h>
  21. #include <stdio.h>
  22. #include <mmsystem.h>
  23. #include <dxerr9.h>
  24. #include <dplay8.h>
  25. #include <dpaddr.h>
  26. #include <dplobby8.h>
  27. #include "NetConnect.h"
  28. #include "NetConnectRes.h"
  29. #include "DXUtil.h"
  30.  
  31. #if defined(WIN32_PLATFORM_PSPC) && (_WIN32_WCE >= 300)
  32. #include <aygshell.h>
  33. #endif // PocketPC
  34.  
  35.  
  36.  
  37. //-----------------------------------------------------------------------------
  38. // Global variables
  39. //-----------------------------------------------------------------------------
  40. CNetConnectWizard* g_pNCW = NULL;           // Pointer to the net connect wizard
  41.  
  42.  
  43.  
  44.  
  45. //-----------------------------------------------------------------------------
  46. // Name: CNetConnectWizard
  47. // Desc: Init the class
  48. //-----------------------------------------------------------------------------
  49. CNetConnectWizard::CNetConnectWizard( HINSTANCE hInst, HWND hWndParent, 
  50.                                       TCHAR* strAppName, GUID* pGuidApp )
  51. {
  52.     g_pNCW              = this;
  53.     m_hInst             = hInst;
  54.     m_hWndParent        = hWndParent;
  55.     m_pDP               = NULL;
  56.     m_pLobbiedApp       = NULL;
  57.     m_bHaveConnectionSettingsFromLobby = FALSE;
  58.     m_hLobbyClient      = NULL;
  59.     m_guidApp           = *pGuidApp;
  60.     m_hDlg              = NULL;
  61.     m_bConnecting       = FALSE;
  62.     m_hConnectAsyncOp   = NULL;
  63.     m_hEnumAsyncOp      = NULL;
  64.     m_bMigrateHost      = FALSE;
  65.     m_bUseDPNSVR        = FALSE;
  66.     m_dwPort            = 0;
  67.     m_eSigningType      = SIGN_NONE;
  68.     m_dwEnumHostExpireInterval = 0;
  69.  
  70.     ZeroMemory(&m_guidSP, sizeof(GUID));
  71.  
  72.     // Set the max players unlimited by default.  This can be changed by the app
  73.     // by calling SetMaxPlayers()
  74.     m_dwMaxPlayers   = 0;
  75.  
  76.     _tcsncpy( m_strAppName, strAppName, MAX_PATH-1 );
  77.     m_strAppName[ MAX_PATH-1 ] = 0; 
  78.     
  79.     _tcsncpy( m_strPreferredProvider, TEXT("DirectPlay8 TCP/IP Service Provider"), MAX_PATH-1 );
  80.     m_strPreferredProvider[ MAX_PATH-1 ] = 0; 
  81.  
  82.     _tcsncpy( m_strHostname, TEXT(""), MAX_PATH-1 );
  83.  
  84.     InitializeCriticalSection( &m_csHostEnum );
  85.     m_hConnectCompleteEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
  86.     m_hLobbyConnectionEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
  87.  
  88.     // Setup the m_DPHostEnumHead circular linked list
  89.     ZeroMemory( &m_DPHostEnumHead, sizeof( DPHostEnumInfo ) );
  90.     m_DPHostEnumHead.pNext = &m_DPHostEnumHead;
  91. }
  92.  
  93.  
  94.  
  95.  
  96. //-----------------------------------------------------------------------------
  97. // Name: ~CNetConnectWizard
  98. // Desc: Cleanup the class
  99. //-----------------------------------------------------------------------------
  100. CNetConnectWizard::~CNetConnectWizard()
  101. {
  102.     DeleteCriticalSection( &m_csHostEnum );
  103.     CloseHandle( m_hConnectCompleteEvent );
  104.     CloseHandle( m_hLobbyConnectionEvent );
  105. }
  106.  
  107.  
  108.  
  109. //-----------------------------------------------------------------------------
  110. // Name: Init
  111. // Desc:
  112. //-----------------------------------------------------------------------------
  113. HRESULT CNetConnectWizard::Init( IDirectPlay8Peer* pDP,
  114.                                  IDirectPlay8LobbiedApplication* pLobbiedApp )
  115. {
  116.     if( NULL == pDP || NULL == pLobbiedApp )
  117.         return E_INVALIDARG;
  118.  
  119.     m_pDP               = pDP;
  120.     m_pLobbiedApp       = pLobbiedApp;
  121.     m_bHaveConnectionSettingsFromLobby = FALSE;
  122.     m_hLobbyClient      = NULL;
  123.  
  124.     return S_OK;
  125. }
  126.  
  127.  
  128.  
  129. //-----------------------------------------------------------------------------
  130. // Name: Shutdown
  131. // Desc: Releases the DirectPlay interfaces
  132. //-----------------------------------------------------------------------------
  133. VOID CNetConnectWizard::Shutdown()
  134. {
  135. }
  136.  
  137.  
  138.  
  139.  
  140. //-----------------------------------------------------------------------------
  141. // Name: DoConnectWizard
  142. // Desc: This is the main external function.  This will launch a series of
  143. //       dialog boxes that enumerate service providers, enumerate hosts,
  144. //       and allow the user to either join or host a session
  145. //-----------------------------------------------------------------------------
  146. HRESULT CNetConnectWizard::DoConnectWizard( BOOL bBackTrack )
  147. {
  148.     if( m_pDP == NULL )
  149.         return E_INVALIDARG;
  150.  
  151.     int nStep;
  152.  
  153.     // If the back track flag is true, then the user has already been through
  154.     // the connect process once, and has back tracked out of the main game
  155.     // so start at the last dialog box
  156.     if( bBackTrack )
  157.         nStep = 1;
  158.     else
  159.         nStep = 0;
  160.  
  161.     // Show the dialog boxes to connect
  162.     for( ;; )
  163.     {
  164.         m_hrDialog = S_OK;
  165.  
  166.         switch( nStep )
  167.         {
  168.             case 0:
  169.                 // Display the multiplayer connect dialog box.
  170.                 DialogBox( m_hInst, MAKEINTRESOURCE(IDD_MULTIPLAYER_CONNECT),
  171.                            m_hWndParent, (DLGPROC) StaticConnectionsDlgProc );
  172.                 break;
  173.  
  174.             case 1:
  175.                 // Display the multiplayer games dialog box.
  176.                 DialogBox( m_hInst, MAKEINTRESOURCE(IDD_MULTIPLAYER_GAMES),
  177.                            m_hWndParent, (DLGPROC) StaticSessionsDlgProc );
  178.                 break;
  179.         }
  180.  
  181.         if( FAILED( m_hrDialog ) ||
  182.             m_hrDialog == NCW_S_QUIT ||
  183.             m_hrDialog == NCW_S_LOBBYCONNECT )
  184.             break;
  185.  
  186.         if( m_hrDialog == NCW_S_BACKUP )
  187.             nStep--;
  188.         else
  189.             nStep++;
  190.  
  191.         // If we go beyond the last step in the wizard, then stop
  192.         // and return.
  193.         if( nStep == 2 )
  194.             break;
  195.     }
  196.  
  197.     // Depending upon a successful m_hrDialog the user has
  198.     // either successfully join or created a game, depending on m_bHostPlayer
  199.     m_pDP = NULL;
  200.     return m_hrDialog;
  201. }
  202.  
  203.  
  204.  
  205.  
  206. //-----------------------------------------------------------------------------
  207. // Name: StaticConnectionsDlgProc()
  208. // Desc: Static msg handler which passes messages
  209. //-----------------------------------------------------------------------------
  210. INT_PTR CALLBACK CNetConnectWizard::StaticConnectionsDlgProc( HWND hDlg, UINT uMsg,
  211.                                                               WPARAM wParam, LPARAM lParam )
  212. {
  213.     if( g_pNCW )
  214.         return g_pNCW->ConnectionsDlgProc( hDlg, uMsg, wParam, lParam );
  215.  
  216.     return FALSE; // Message not handled
  217. }
  218.  
  219.  
  220.  
  221.  
  222. //-----------------------------------------------------------------------------
  223. // Name: ConnectionsDlgProc()
  224. // Desc: Handles messages for the multiplayer connect dialog
  225. //-----------------------------------------------------------------------------
  226. INT_PTR CALLBACK CNetConnectWizard::ConnectionsDlgProc( HWND hDlg, UINT msg,
  227.                                                         WPARAM wParam, LPARAM lParam )
  228. {
  229.     UNREFERENCED_PARAMETER( lParam );
  230.     
  231.     switch( msg )
  232.     {
  233.         case WM_INITDIALOG:
  234.             {
  235. #if defined(WIN32_PLATFORM_PSPC) && (_WIN32_WCE >= 300)
  236.                 SHINITDLGINFO   shidi;
  237.                 memset(&shidi, 0, sizeof(SHINITDLGINFO));
  238.                 shidi.dwMask = SHIDIM_FLAGS;
  239.                 shidi.dwFlags = SHIDIF_SIPDOWN | SHIDIF_SIZEDLGFULLSCREEN;
  240.                 shidi.hDlg = hDlg;
  241.  
  242.                 SetForegroundWindow(hDlg);
  243.                 SHInitDialog(&shidi);
  244. #endif // WIN32_PLATFORM_PSPC
  245.  
  246.                 SetDlgItemText( hDlg, IDC_PLAYER_NAME_EDIT, m_strLocalPlayerName );
  247.  
  248.                 // Load and set the icon
  249.                 HICON hIcon = LoadIcon( m_hInst, MAKEINTRESOURCE( IDI_MAIN ) );
  250.                 SendMessage( hDlg, WM_SETICON, ICON_BIG,   (LPARAM) hIcon );  // Set big icon
  251.                 SendMessage( hDlg, WM_SETICON, ICON_SMALL, (LPARAM) hIcon );  // Set small icon
  252.  
  253.                 // Set the window title
  254.                 TCHAR strWindowTitle[256];
  255.                 wsprintf( strWindowTitle, TEXT("%s - Multiplayer Connect"), m_strAppName );
  256.                 SetWindowText( hDlg, strWindowTitle );
  257.  
  258.                 // Fill the list box with the service providers
  259.                 if( FAILED( m_hrDialog = ConnectionsDlgFillListBox( hDlg ) ) )
  260.                 {
  261.                     DXTRACE_ERR_MSGBOX( TEXT("ConnectionsDlgFillListBox"), m_hrDialog );
  262.                     EndDialog( hDlg, 0 );
  263.                 }
  264.             }
  265.             break;
  266.  
  267.         case WM_COMMAND:
  268.             switch( LOWORD(wParam) )
  269.             {
  270.                 case IDC_CONNECTION_LIST:
  271.                     if( HIWORD(wParam) != LBN_DBLCLK )
  272.                         break;
  273.                     // Fall through
  274.  
  275.                 case IDOK:
  276.                     if( FAILED( m_hrDialog = ConnectionsDlgOnOK( hDlg ) ) )
  277.                     {
  278.                         DXTRACE_ERR_MSGBOX( TEXT("ConnectionsDlgOnOK"), m_hrDialog );
  279.                         EndDialog( hDlg, 0 );
  280.                     }
  281.  
  282.                     if( m_hrDialog == NCW_S_LOBBYCONNECT )
  283.                     {
  284.                         EndDialog( hDlg, 0 );
  285.                     }
  286.                     break;
  287.  
  288.                 case IDCANCEL:
  289.                     m_hrDialog = NCW_S_QUIT;
  290.                     EndDialog( hDlg, 0 );
  291.                     break;
  292.  
  293.                 default:
  294.                     return FALSE; // Message not handled
  295.             }
  296.             break;
  297.  
  298.         case WM_DESTROY:
  299.             ConnectionsDlgCleanup( hDlg );
  300.             break;
  301.  
  302.         default:
  303.             return FALSE; // Message not handled
  304.     }
  305.  
  306.     // Message was handled
  307.     return TRUE;
  308. }
  309.  
  310.  
  311.  
  312.  
  313. //-----------------------------------------------------------------------------
  314. // Name: ConnectionsDlgFillListBox()
  315. // Desc: Fills the DirectPlay connection listbox with service providers,
  316. //       and also adds a "Wait for Lobby" connection option.
  317. //-----------------------------------------------------------------------------
  318. HRESULT CNetConnectWizard::ConnectionsDlgFillListBox( HWND hDlg )
  319. {
  320.     HRESULT                     hr;
  321.     int                         iLBIndex;
  322.     DWORD                       dwItems     = 0;
  323.     DPN_SERVICE_PROVIDER_INFO*  pdnSPInfo   = NULL;
  324.     DWORD                       dwSize      = 0;
  325.     HWND                        hWndListBox = GetDlgItem( hDlg, IDC_CONNECTION_LIST );
  326.     TCHAR                       strName[MAX_PATH];
  327.  
  328.     // Enumerate all DirectPlay service providers, and store them in the listbox
  329.  
  330.     // Get required space for all providers
  331.     hr = m_pDP->EnumServiceProviders( NULL, NULL, pdnSPInfo, &dwSize,
  332.                                       &dwItems, 0 );
  333.     if( FAILED(hr) && hr != DPNERR_BUFFERTOOSMALL )
  334.     {
  335.         DXTRACE_ERR_MSGBOX( TEXT("EnumServiceProviders"), hr );
  336.         goto LCleanReturn;
  337.     }
  338.  
  339.     // Allocate required space
  340.     pdnSPInfo = (DPN_SERVICE_PROVIDER_INFO*) new BYTE[dwSize];
  341.     if( NULL == pdnSPInfo )
  342.     {
  343.         hr = E_OUTOFMEMORY;
  344.         DXTRACE_ERR_MSGBOX( TEXT("ConnectionsDlgFillListBox"), hr );
  345.         goto LCleanReturn;
  346.     }
  347.  
  348.     // Perform the enumeration
  349.     hr = m_pDP->EnumServiceProviders( NULL, NULL, pdnSPInfo,
  350.                                       &dwSize, &dwItems, 0 );
  351.     if( FAILED(hr) )
  352.     {
  353.         DXTRACE_ERR_MSGBOX( TEXT("EnumServiceProviders"), hr );
  354.         goto LCleanReturn;
  355.     }
  356.  
  357.     // For each detected provider, add an item to the listbox
  358.     DPN_SERVICE_PROVIDER_INFO* pdnSPInfoEnum;
  359.     pdnSPInfoEnum = pdnSPInfo;
  360.  
  361.     DWORD i;
  362.     for ( i = 0; i < dwItems; i++ )
  363.     {
  364.         DXUtil_ConvertWideStringToGenericCch( strName, pdnSPInfoEnum->pwszName, MAX_PATH );
  365.  
  366.         // Found a service provider, so put it in the listbox
  367.         iLBIndex = (int)SendMessage( hWndListBox, LB_ADDSTRING, 0,
  368.                                      (LPARAM)strName );
  369.         if( iLBIndex == CB_ERR )
  370.         {
  371.             // Error, stop enumerating
  372.             hr = E_FAIL;
  373.             DXTRACE_ERR_MSGBOX( TEXT("ConnectionsDlgFillListBox"), hr );
  374.             goto LCleanReturn;
  375.         }
  376.  
  377.         // Store pointer to GUID in listbox
  378.         GUID* pGuid = new GUID;
  379.         if( NULL == pGuid )
  380.         {
  381.             hr = E_OUTOFMEMORY;
  382.             DXTRACE_ERR_MSGBOX( TEXT("ConnectionsDlgFillListBox"), hr );
  383.             goto LCleanReturn;
  384.         }
  385.  
  386.         memcpy( pGuid, &pdnSPInfoEnum->guid, sizeof(GUID) );
  387.         SendMessage( hWndListBox, LB_SETITEMDATA, iLBIndex,
  388.                      (LPARAM)pGuid );
  389.  
  390.         // Advance to next provider
  391.         pdnSPInfoEnum++;
  392.     }
  393.  
  394.     // Add "Wait for Lobby Connection" selection in list box
  395.     SendMessage( hWndListBox, LB_ADDSTRING, 0,
  396.                  (LPARAM) TEXT("Wait for Lobby Connection") );
  397.  
  398.     SetFocus( hWndListBox );
  399.  
  400.     // Try to select the default preferred provider
  401.     iLBIndex = (int)SendMessage( hWndListBox, LB_FINDSTRINGEXACT, (WPARAM)-1,
  402.                                 (LPARAM)m_strPreferredProvider );
  403.     if( iLBIndex != LB_ERR )
  404.         SendMessage( hWndListBox, LB_SETCURSEL, iLBIndex, 0 );
  405.     else
  406.         SendMessage( hWndListBox, LB_SETCURSEL, 0, 0 );
  407.  
  408.  
  409.     hr = S_OK;
  410.  
  411. LCleanReturn:
  412.     SAFE_DELETE_ARRAY( pdnSPInfo );
  413.  
  414.     return hr;
  415. }
  416.  
  417.  
  418.  
  419.  
  420. //-----------------------------------------------------------------------------
  421. // Name: ConnectionsDlgOnOK()
  422. // Desc: Stores the player name m_strPlayerName, and in creates a IDirectPlay
  423. //       object based on the connection type the user selected.
  424. //-----------------------------------------------------------------------------
  425. HRESULT CNetConnectWizard::ConnectionsDlgOnOK( HWND hDlg )
  426. {
  427.     LRESULT iIndex;
  428.     HRESULT hr;
  429.  
  430.     GetDlgItemText( hDlg, IDC_PLAYER_NAME_EDIT, m_strLocalPlayerName, MAX_PATH );
  431.  
  432.     if( _tcslen( m_strLocalPlayerName ) == 0 )
  433.     {
  434.         MessageBox( hDlg, TEXT("You must enter a valid player name."),
  435.                     TEXT("DirectPlay Sample"), MB_OK );
  436.         return S_OK;
  437.     }
  438.  
  439.     HWND hWndListBox = GetDlgItem( hDlg, IDC_CONNECTION_LIST );
  440.  
  441.     iIndex = SendMessage( hWndListBox, LB_GETCURSEL, 0, 0 );
  442.     SendMessage( hWndListBox, LB_GETTEXT, iIndex, (LPARAM)m_strPreferredProvider );
  443.  
  444.     GUID* pGuid = (GUID*) SendMessage( hWndListBox, LB_GETITEMDATA, iIndex, 0 );
  445.     if( NULL == pGuid )
  446.     {
  447.         // 'Wait for lobby launch' SP has been selected, so wait for a connection
  448.         if( FAILED( hr = m_pLobbiedApp->SetAppAvailable( TRUE, 0 ) ) )
  449.             return DXTRACE_ERR_MSGBOX( TEXT("SetAppAvailable"), hr );
  450.  
  451.         // Display the multiplayer connect dialog box.
  452.         DialogBox( m_hInst, MAKEINTRESOURCE(IDD_LOBBY_WAIT_STATUS),
  453.                    hDlg, (DLGPROC) StaticLobbyWaitDlgProc );
  454.  
  455.         if( m_bHaveConnectionSettingsFromLobby )
  456.         {
  457.             if( FAILED( hr = ConnectUsingLobbySettings() ) )
  458.                 return DXTRACE_ERR_MSGBOX( TEXT("ConnectUsingLobbySettings"), hr );
  459.  
  460.             return NCW_S_LOBBYCONNECT;
  461.         }
  462.  
  463.         // 'Wait for lobby launch' was canceled, so don't wait for a connection anymore
  464.         if( FAILED( hr = m_pLobbiedApp->SetAppAvailable( FALSE, 0 ) ) )
  465.             return DXTRACE_ERR_MSGBOX( TEXT("SetAppAvailable"), hr );
  466.  
  467.         return S_OK;
  468.     }
  469.  
  470.     // Query for the enum host timeout for this SP
  471.     DPN_SP_CAPS dpspCaps;
  472.     ZeroMemory( &dpspCaps, sizeof(DPN_SP_CAPS) );
  473.     dpspCaps.dwSize = sizeof(DPN_SP_CAPS);
  474.     if( FAILED( hr = m_pDP->GetSPCaps( pGuid, &dpspCaps, 0 ) ) )
  475.         return DXTRACE_ERR_MSGBOX( TEXT("GetSPCaps"), hr );
  476.  
  477.     // Set the host expire time to around 3 times
  478.     // length of the dwDefaultEnumRetryInterval
  479.     m_dwEnumHostExpireInterval = dpspCaps.dwDefaultEnumRetryInterval * 3;
  480.  
  481.     m_guidSP = *pGuid;
  482.  
  483.     // The SP has been chosen, so move forward in the wizard
  484.     m_hrDialog = NCW_S_FORWARD;
  485.     EndDialog( hDlg, 0 );
  486.  
  487.     return S_OK;
  488. }
  489.  
  490.  
  491.  
  492.  
  493. //-----------------------------------------------------------------------------
  494. // Name: ConnectionsDlgCleanup()
  495. // Desc: Deletes the connection buffers from the listbox
  496. //-----------------------------------------------------------------------------
  497. VOID CNetConnectWizard::ConnectionsDlgCleanup( HWND hDlg )
  498. {
  499.     GUID*   pGuid = NULL;
  500.     DWORD   iIndex;
  501.     DWORD   dwCount;
  502.  
  503.     HWND hWndListBox = GetDlgItem( hDlg, IDC_CONNECTION_LIST );
  504.  
  505.     dwCount = (DWORD)SendMessage( hWndListBox, LB_GETCOUNT, 0, 0 );
  506.     for( iIndex = 0; iIndex < dwCount; iIndex++ )
  507.     {
  508.         pGuid = (GUID*) SendMessage( hWndListBox, LB_GETITEMDATA,
  509.                                      iIndex, 0 );
  510.         SAFE_DELETE( pGuid );
  511.     }
  512. }
  513.  
  514.  
  515.  
  516.  
  517. //-----------------------------------------------------------------------------
  518. // Name: StaticSessionsDlgProc()
  519. // Desc: Static msg handler which passes messages
  520. //-----------------------------------------------------------------------------
  521. INT_PTR CALLBACK CNetConnectWizard::StaticSessionsDlgProc( HWND hDlg, UINT uMsg,
  522.                                                            WPARAM wParam, LPARAM lParam )
  523. {
  524.     if( g_pNCW )
  525.         return g_pNCW->SessionsDlgProc( hDlg, uMsg, wParam, lParam );
  526.  
  527.     return FALSE; // Message not handled
  528. }
  529.  
  530.  
  531.  
  532.  
  533. //-----------------------------------------------------------------------------
  534. // Name: SessionsDlgProc()
  535. // Desc: Handles messages fro the multiplayer games dialog
  536. //-----------------------------------------------------------------------------
  537. INT_PTR CALLBACK CNetConnectWizard::SessionsDlgProc( HWND hDlg, UINT msg,
  538.                                                      WPARAM wParam, LPARAM lParam )
  539. {
  540.     UNREFERENCED_PARAMETER( lParam );
  541.     HRESULT hr;
  542.  
  543.     switch( msg )
  544.     {
  545.         case WM_INITDIALOG:
  546.             {
  547. #if defined(WIN32_PLATFORM_PSPC) && (_WIN32_WCE >= 300)
  548.                 SHINITDLGINFO   shidi;
  549.                 memset(&shidi, 0, sizeof(SHINITDLGINFO));
  550.                 shidi.dwMask = SHIDIM_FLAGS;
  551.                 shidi.dwFlags = SHIDIF_SIPDOWN | SHIDIF_SIZEDLGFULLSCREEN;
  552.                 shidi.hDlg = hDlg;
  553.  
  554.                 SetForegroundWindow(hDlg);
  555.                 SHInitDialog(&shidi);
  556. #endif // WIN32_PLATFORM_PSPC
  557.  
  558.                 m_hDlg = hDlg;
  559.  
  560.                 // Load and set the icon
  561.                 HICON hIcon = LoadIcon( m_hInst, MAKEINTRESOURCE( IDI_MAIN ) );
  562.                 SendMessage( hDlg, WM_SETICON, ICON_BIG,   (LPARAM) hIcon );  // Set big icon
  563.                 SendMessage( hDlg, WM_SETICON, ICON_SMALL, (LPARAM) hIcon );  // Set small icon
  564.  
  565.                 // Set the window title
  566.                 TCHAR strWindowTitle[256];
  567.                 wsprintf( strWindowTitle, TEXT("%s - Multiplayer Games"), m_strAppName );
  568.                 SetWindowText( hDlg, strWindowTitle );
  569.  
  570.                 // Init the search portion of the dialog
  571.                 m_bSearchingForSessions = FALSE;
  572.                 
  573.                 // Check to see if a former search is still waiting to end
  574.                 if(m_hEnumAsyncOp != NULL)
  575.                 {
  576.                     EnableWindow( GetDlgItem(hDlg, IDC_SEARCH_CHECK), FALSE );
  577.                     SetDlgItemText( hDlg, IDC_SEARCH_CHECK, TEXT("Stopping...") );
  578.                 }
  579.  
  580.                 SessionsDlgInitListbox( hDlg );
  581.             }
  582.             break;
  583.  
  584.         case WM_TIMER:
  585.             // Upon this timer message, then refresh the list of hosts
  586.             // by expiring old hosts, and displaying the list in the
  587.             // dialog box
  588.             if( wParam == TIMERID_DISPLAY_HOSTS )
  589.             {
  590.                 // Don't refresh if we are not enumerating hosts
  591.                 if( !m_bSearchingForSessions )
  592.                     break;
  593.  
  594.                 // Expire all of the hosts that haven't
  595.                 // refreshed in a certain period of time
  596.                 SessionsDlgExpireOldHostEnums();
  597.  
  598.                 // Display the list of hosts in the dialog
  599.                 if( FAILED( hr = SessionsDlgDisplayEnumList( hDlg ) ) )
  600.                 {
  601.                     DXTRACE_ERR_MSGBOX( TEXT("SessionsDlgDisplayEnumList"), hr );
  602.                     KillTimer( hDlg, TIMERID_DISPLAY_HOSTS );
  603.                     MessageBox( hDlg, TEXT("Error enumerating DirectPlay games."),
  604.                                 TEXT("DirectPlay Sample"),
  605.                                 MB_OK | MB_ICONERROR );
  606.                 }
  607.             }
  608.             else if( wParam == TIMERID_CONNECT_COMPLETE )
  609.             {
  610.                 // Check to see if the MessageHandler has set an event to tell us the
  611.                 // DPN_MSGID_CONNECT_COMPLETE has been processed.  Now m_hrConnectComplete
  612.                 // is valid.
  613.                 if( WAIT_OBJECT_0 == WaitForSingleObject( m_hConnectCompleteEvent, 0 ) )
  614.                 {
  615.                     m_bConnecting = FALSE;
  616.  
  617.                     // Re-enable create button
  618.                     EnableWindow( GetDlgItem( hDlg, IDC_CREATE ), TRUE );
  619.  
  620.                     if( FAILED( m_hrConnectComplete ) )
  621.                     {
  622.                         DXTRACE_ERR_MSGBOX( TEXT("DPN_MSGID_CONNECT_COMPLETE"), m_hrConnectComplete );
  623.                         MessageBox( m_hDlg, TEXT("Unable to join game."),
  624.                                     TEXT("DirectPlay Sample"),
  625.                                     MB_OK | MB_ICONERROR );
  626.                     }
  627.                     else
  628.                     {
  629.                         // DirectPlay connect successful, so end dialog
  630.                         m_hrDialog = NCW_S_FORWARD;
  631.                         EndDialog( m_hDlg, 0 );
  632.                     }
  633.  
  634.                     KillTimer( hDlg, TIMERID_CONNECT_COMPLETE );
  635.                 }
  636.             }
  637.  
  638.             break;
  639.  
  640.         case WM_COMMAND:
  641.             switch( LOWORD(wParam) )
  642.             {
  643.                 case IDC_SEARCH_CHECK:
  644.                     m_bSearchingForSessions = !m_bSearchingForSessions;
  645.  
  646.                     if( m_bSearchingForSessions )
  647.                     {
  648.                         // Ask the user for the remote address
  649.                         if( SPRequiresPort( &m_guidSP ) )
  650.                         {
  651.                             int nResult = (int)DialogBox( m_hInst, MAKEINTRESOURCE(IDD_MULTIPLAYER_ADDRESS),
  652.                                                           hDlg, (DLGPROC) StaticAddressDlgProc );
  653.                     
  654.                             // If the user cancelled the remote address dialog box, 
  655.                             // don't start the search
  656.                             if( nResult == IDCANCEL )
  657.                             {
  658.                                 m_bSearchingForSessions = FALSE;
  659.                                 break;
  660.                             }
  661.                         }
  662.  
  663.                         SetDlgItemText( hDlg, IDC_SEARCH_CHECK, TEXT("Searching...") );
  664.  
  665.                         // Start the timer to display the host list every so often
  666.                         SetTimer( hDlg, TIMERID_DISPLAY_HOSTS, DISPLAY_REFRESH_RATE, NULL );
  667.  
  668.                         // Start the async enumeration
  669.                         if( FAILED( hr = SessionsDlgEnumHosts( hDlg ) ) )
  670.                         {
  671.                             DXTRACE_ERR_MSGBOX( TEXT("SessionsDlgEnumHosts"), hr );
  672.                             KillTimer( hDlg, TIMERID_DISPLAY_HOSTS );
  673.                             MessageBox( hDlg, TEXT("Error enumerating DirectPlay games."),
  674.                                         TEXT("DirectPlay Sample"),
  675.                                         MB_OK | MB_ICONERROR );
  676.                         }
  677.                     }
  678.                     else
  679.                     {
  680.                         SessionsDlgStopEnumHosts( hDlg );
  681.                     }
  682.  
  683.                     break;
  684.  
  685.                 case IDC_GAMES_LIST:
  686.                     if( HIWORD(wParam) != LBN_DBLCLK )
  687.                         break;
  688.                     // Fall through
  689.  
  690.                 case IDC_JOIN:
  691.                     if( FAILED( hr = SessionsDlgJoinGame( hDlg ) ) )
  692.                     {
  693.                         DXTRACE_ERR_MSGBOX( TEXT("SessionsDlgJoinGame"), hr );
  694.                         MessageBox( hDlg, TEXT("Unable to join game."),
  695.                                     TEXT("DirectPlay Sample"),
  696.                                     MB_OK | MB_ICONERROR );
  697.                     }
  698.                     break;
  699.  
  700.                 case IDC_CREATE:
  701.                     if( FAILED( hr = SessionsDlgCreateGame( hDlg ) ) )
  702.                     {
  703.                         DXTRACE_ERR_MSGBOX( TEXT("SessionsDlgCreateGame"), hr );
  704.                         MessageBox( hDlg, TEXT("Unable to create game."),
  705.                                     TEXT("DirectPlay Sample"),
  706.                                     MB_OK | MB_ICONERROR );
  707.                     }
  708.                     break;
  709.  
  710.                 case IDCANCEL: // The close button was press
  711.                     m_hrDialog = NCW_S_QUIT;
  712.                     EndDialog(hDlg, 0);
  713.                     break;
  714.  
  715.                 case IDC_BACK: // Cancel button was pressed
  716.                     m_hrDialog = NCW_S_BACKUP;
  717.                     EndDialog(hDlg, 0);
  718.                     break;
  719.  
  720.                 default:
  721.                     return FALSE; // Message not handled
  722.             }
  723.             break;
  724.         
  725.             case WM_DESTROY:
  726.                 SessionsDlgStopEnumHosts(hDlg);
  727.                 break;
  728.  
  729.         default:
  730.             return FALSE; // Message not handled
  731.     }
  732.  
  733.     // Message was handled
  734.     return TRUE;
  735. }
  736.  
  737.  
  738.  
  739.  
  740. //-----------------------------------------------------------------------------
  741. // Name: SessionsDlgInitListbox()
  742. // Desc: Initializes the listbox
  743. //-----------------------------------------------------------------------------
  744. VOID CNetConnectWizard::SessionsDlgInitListbox( HWND hDlg )
  745. {
  746.     HWND hWndListBox = GetDlgItem( hDlg, IDC_GAMES_LIST );
  747.  
  748.     // Clear the contents from the list box, and
  749.     // display "Looking for games" text in listbox
  750.     SendMessage( hWndListBox, LB_RESETCONTENT, 0, 0 );
  751.     if( m_bSearchingForSessions )
  752.     {
  753.         SendMessage( hWndListBox, LB_ADDSTRING, 0,
  754.                      (LPARAM) TEXT("Looking for games...") );
  755.     }
  756.     else
  757.     {
  758.         SendMessage( hWndListBox, LB_ADDSTRING, 0,
  759.                      (LPARAM) TEXT("Click Start Search to see a list of games."));
  760.         SendMessage( hWndListBox, LB_ADDSTRING, 0,
  761.                      (LPARAM) TEXT("Click Create to start a new game.") );
  762.     }
  763.  
  764.     SendMessage( hWndListBox, LB_SETITEMDATA,  0, NULL );
  765.     SendMessage( hWndListBox, LB_SETCURSEL,    0, 0 );
  766.  
  767.     // Disable the join button until sessions are found
  768.     EnableWindow( GetDlgItem( hDlg, IDC_JOIN ), FALSE );
  769. }
  770.  
  771.  
  772.  
  773.  
  774. //-----------------------------------------------------------------------------
  775. // Name: SessionsDlgEnumHosts()
  776. // Desc: Enumerates the DirectPlay sessions, and displays them in the listbox
  777. //-----------------------------------------------------------------------------
  778. HRESULT CNetConnectWizard::SessionsDlgEnumHosts( HWND hDlg )
  779. {
  780.     UNREFERENCED_PARAMETER( hDlg );
  781.     HRESULT hr = S_OK;
  782.  
  783.     m_bEnumListChanged = TRUE;
  784.  
  785.     IDirectPlay8Address*   pDP8AddressHost  = NULL;
  786.     IDirectPlay8Address*   pDP8AddressLocal = NULL;
  787.     WCHAR*                 wszHostName      = NULL;
  788.  
  789.     // Create the local device address object
  790.     if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay8Address, NULL, 
  791.                                        CLSCTX_ALL, IID_IDirectPlay8Address,
  792.                                        (LPVOID*) &pDP8AddressLocal ) ) )
  793.     {
  794.         DXTRACE_ERR_MSGBOX( TEXT("CoCreateInstance"), hr );
  795.         goto LCleanup;
  796.     }
  797.  
  798.     // Set local service provider
  799.     if( FAILED( hr = pDP8AddressLocal->SetSP( &m_guidSP ) ) )
  800.     {
  801.         DXTRACE_ERR_MSGBOX( TEXT("SetSP"), hr );
  802.         goto LCleanup;
  803.     }
  804.  
  805.     // Create the remote host address object
  806.     if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay8Address, NULL, 
  807.                                        CLSCTX_ALL, IID_IDirectPlay8Address,
  808.                                        (LPVOID*) &pDP8AddressHost ) ) )
  809.     {
  810.         DXTRACE_ERR_MSGBOX( TEXT("CoCreateInstance"), hr );
  811.         goto LCleanup;
  812.     }
  813.  
  814.     // Set remote service provider
  815.     if( FAILED( hr = pDP8AddressHost->SetSP( &m_guidSP ) ) )
  816.     {
  817.         DXTRACE_ERR_MSGBOX( TEXT("SetSP"), hr );
  818.         goto LCleanup;
  819.     }
  820.  
  821.     // If we're using a TCP/IP (including network simulator) or IPX
  822.     // service provider, the user was given an option for hostname and
  823.     // port before the search started. 
  824.     if( SPRequiresPort( &m_guidSP ) ) 
  825.     {
  826.         // Add the hostname. If this is blank, DirectPlay will attempt
  827.         // to search the local network.
  828.         if( _tcscmp(m_strHostname, TEXT("")) != 0 )
  829.         {
  830.             WCHAR wszHostName[MAX_PATH];
  831.             DXUtil_ConvertGenericStringToWideCch( wszHostName, m_strHostname, MAX_PATH );
  832.             hr = pDP8AddressHost->AddComponent( DPNA_KEY_HOSTNAME, wszHostName, 
  833.                                                 (DWORD) (wcslen(wszHostName)+1)*sizeof(WCHAR), 
  834.                                                 DPNA_DATATYPE_STRING );
  835.             if( FAILED(hr) )
  836.             {
  837.                 DXTRACE_ERR_MSGBOX( TEXT("AddComponent"), hr );
  838.                 goto LCleanup;
  839.             }
  840.         }
  841.  
  842.         // Add the requested port value. The port value is required in order to
  843.         // receive any search hits if DPNSVR isn't running on the remote machine.
  844.         // Games will typically hard code the port so the user need not know it
  845.         if( m_dwPort != 0 )
  846.         {
  847.             hr = pDP8AddressHost->AddComponent( DPNA_KEY_PORT, 
  848.                                                 &m_dwPort, sizeof(m_dwPort),
  849.                                                 DPNA_DATATYPE_DWORD );
  850.             if( FAILED(hr) )
  851.             {
  852.                 DXTRACE_ERR_MSGBOX( TEXT("AddComponent"), hr );
  853.                 goto LCleanup;
  854.             }
  855.         }
  856.     }
  857.  
  858.     // Enumerate hosts
  859.     DPN_APPLICATION_DESC    dnAppDesc;
  860.     ZeroMemory( &dnAppDesc, sizeof(DPN_APPLICATION_DESC) );
  861.     dnAppDesc.dwSize          = sizeof(DPN_APPLICATION_DESC);
  862.     dnAppDesc.guidApplication = m_guidApp;
  863.  
  864.     DWORD dwFlags;
  865.     dwFlags = 0;
  866.  
  867.     // For certain service providers the user has not been
  868.     // asked to fill in the components of the remote address,
  869.     // so DirectPlay should ask for required fields.
  870.     if( !SPRequiresPort( &m_guidSP ) )
  871.     {
  872.         dwFlags = DPNENUMHOSTS_OKTOQUERYFORADDRESSING;
  873.     }
  874.  
  875.     // Enumerate all the active DirectPlay games on the selected connection
  876.     hr = m_pDP->EnumHosts( &dnAppDesc,                            // application description
  877.                            pDP8AddressHost,                       // host address
  878.                            pDP8AddressLocal,                      // device address
  879.                            NULL,                                  // pointer to user data
  880.                            0,                                     // user data size
  881.                            INFINITE,                              // retry count (forever)
  882.                            0,                                     // retry interval (0=default)
  883.                            INFINITE,                              // time out (forever)
  884.                            NULL,                                  // user context
  885.                            &m_hEnumAsyncOp,                       // async handle
  886.                            dwFlags                                // flags
  887.                            );
  888.     if( FAILED(hr) )
  889.     {
  890.         DXTRACE_ERR_MSGBOX( TEXT("EnumHosts"), hr );
  891.         goto LCleanup;
  892.     }
  893.  
  894. LCleanup:
  895.     SAFE_RELEASE( pDP8AddressHost);
  896.     SAFE_RELEASE( pDP8AddressLocal );
  897.     SAFE_DELETE( wszHostName );
  898.  
  899.     return hr;
  900. }
  901.  
  902.  
  903.  
  904.  
  905. //-----------------------------------------------------------------------------
  906. // Name: SessionsDlgStopEnumHosts()
  907. // Desc: Stops the running session enumeration
  908. //-----------------------------------------------------------------------------
  909. VOID CNetConnectWizard::SessionsDlgStopEnumHosts( HWND hDlg )
  910. {
  911.     HRESULT hr;
  912.  
  913.     // Update the UI 
  914.     EnableWindow( GetDlgItem( hDlg, IDC_SEARCH_CHECK ), FALSE );
  915.     SetDlgItemText( hDlg, IDC_SEARCH_CHECK, TEXT("Stopping...") );
  916.  
  917.     // Stop the timer, and stop the async enumeration
  918.     KillTimer( hDlg, TIMERID_DISPLAY_HOSTS );
  919.  
  920.     // Until the CancelAsyncOperation returns, it is possible
  921.     // to still receive host enumerations. Instruct DirectPlay to
  922.     // stop the current enumeration and handle the rest of the cleanup
  923.     // when receiving the ASYNC_OP_COMPLETE message. If this method
  924.     // fails we should assume there's no active enumeration and call
  925.     // the finalization method directly.
  926.     if( m_hEnumAsyncOp )
  927.     {
  928.         hr = m_pDP->CancelAsyncOperation( m_hEnumAsyncOp, 0 );
  929.         if( FAILED(hr) )
  930.             SessionsDlgFinalizeEnumHosts( hDlg );
  931.     }
  932.     else
  933.     {
  934.         SessionsDlgFinalizeEnumHosts( hDlg );
  935.     }
  936. }
  937.  
  938.  
  939.  
  940.  
  941. //-----------------------------------------------------------------------------
  942. // Name: SessionsDlgFinalizeEnumHosts()
  943. // Desc: This method should be called when we receive confirmation from 
  944. //       DirectPlay that the enumeration has completed. It reset the search
  945. //       UI and state variables, and enables the search button.
  946. //-----------------------------------------------------------------------------
  947. VOID CNetConnectWizard::SessionsDlgFinalizeEnumHosts( HWND hDlg )
  948. {
  949.     // Clear the data list
  950.     SessionsDlgEnumListCleanup();
  951.  
  952.     // Reset the search state variables
  953.     m_hEnumAsyncOp = NULL;
  954.     m_bSearchingForSessions = FALSE;
  955.     
  956.     // Reset the search portion of the dialog
  957.     SessionsDlgInitListbox( hDlg ); 
  958.     CheckDlgButton( hDlg, IDC_SEARCH_CHECK, BST_UNCHECKED );
  959.     SetDlgItemText( hDlg, IDC_SEARCH_CHECK, TEXT("Start &Search") );
  960.     EnableWindow( GetDlgItem( hDlg, IDC_SEARCH_CHECK ), TRUE );
  961. }
  962.  
  963.  
  964.  
  965.  
  966. //-----------------------------------------------------------------------------
  967. // Name: SessionsDlgNoteEnumResponse()
  968. // Desc: Stores them in the linked list, m_DPHostEnumHead.  This is
  969. //       called from the DirectPlay message handler so it could be
  970. //       called simultaneously from multiple threads.
  971. //-----------------------------------------------------------------------------
  972. HRESULT CNetConnectWizard::SessionsDlgNoteEnumResponse( PDPNMSG_ENUM_HOSTS_RESPONSE pEnumHostsResponseMsg )
  973. {
  974.     HRESULT hr = S_OK;
  975.     BOOL    bFound;
  976.  
  977.     // This function is called from the DirectPlay message handler so it could be
  978.     // called simultaneously from multiple threads, so enter a critical section
  979.     // to assure that it we don't get race conditions.  Locking the entire
  980.     // function is crude, and could be more optimal but is effective for this
  981.     // simple sample
  982.     EnterCriticalSection( &m_csHostEnum );
  983.  
  984.     DPHostEnumInfo* pDPHostEnum          = m_DPHostEnumHead.pNext;
  985.     DPHostEnumInfo* pDPHostEnumNext      = NULL;
  986.     const DPN_APPLICATION_DESC* pResponseMsgAppDesc =
  987.                             pEnumHostsResponseMsg->pApplicationDescription;
  988.  
  989.     // Look for a matching session instance GUID.
  990.     bFound = FALSE;
  991.     while ( pDPHostEnum != &m_DPHostEnumHead )
  992.     {
  993.         if( pResponseMsgAppDesc->guidInstance == pDPHostEnum->pAppDesc->guidInstance )
  994.         {
  995.             bFound = TRUE;
  996.             break;
  997.         }
  998.  
  999.         pDPHostEnumNext = pDPHostEnum;
  1000.         pDPHostEnum = pDPHostEnum->pNext;
  1001.     }
  1002.  
  1003.     if( !bFound )
  1004.     {
  1005.         m_bEnumListChanged = TRUE;
  1006.  
  1007.         // If there's no match, then look for invalid session and use it
  1008.         pDPHostEnum = m_DPHostEnumHead.pNext;
  1009.         while ( pDPHostEnum != &m_DPHostEnumHead )
  1010.         {
  1011.             if( !pDPHostEnum->bValid )
  1012.                 break;
  1013.  
  1014.             pDPHostEnum = pDPHostEnum->pNext;
  1015.         }
  1016.  
  1017.         // If no invalid sessions are found then make a new one
  1018.         if( pDPHostEnum == &m_DPHostEnumHead )
  1019.         {
  1020.             // Found a new session, so create a new node
  1021.             pDPHostEnum = new DPHostEnumInfo;
  1022.             if( NULL == pDPHostEnum )
  1023.             {
  1024.                 hr = E_OUTOFMEMORY;
  1025.                 goto LCleanup;
  1026.             }
  1027.  
  1028.             ZeroMemory( pDPHostEnum, sizeof(DPHostEnumInfo) );
  1029.  
  1030.             // Add pDPHostEnum to the circular linked list, m_DPHostEnumHead
  1031.             pDPHostEnum->pNext = m_DPHostEnumHead.pNext;
  1032.             m_DPHostEnumHead.pNext = pDPHostEnum;
  1033.         }
  1034.     }
  1035.  
  1036.     // Update the pDPHostEnum with new information
  1037.     TCHAR strName[MAX_PATH];
  1038.     if( pResponseMsgAppDesc->pwszSessionName )
  1039.     {
  1040.         DXUtil_ConvertWideStringToGenericCch( strName, pResponseMsgAppDesc->pwszSessionName, MAX_PATH );
  1041.     }
  1042.  
  1043.     // Cleanup any old enum
  1044.     if( pDPHostEnum->pAppDesc )
  1045.     {
  1046.         SAFE_DELETE_ARRAY( pDPHostEnum->pAppDesc->pwszSessionName );
  1047.         SAFE_DELETE( pDPHostEnum->pAppDesc );
  1048.     }
  1049.     SAFE_RELEASE( pDPHostEnum->pHostAddr );
  1050.     SAFE_RELEASE( pDPHostEnum->pDeviceAddr );
  1051.  
  1052.     //
  1053.     // Duplicate pEnumHostsResponseMsg->pAddressSender in pDPHostEnum->pHostAddr.
  1054.     // Duplicate pEnumHostsResponseMsg->pAddressDevice in pDPHostEnum->pDeviceAddr.
  1055.     //
  1056.     if( FAILED( hr = pEnumHostsResponseMsg->pAddressSender->Duplicate( &pDPHostEnum->pHostAddr ) ) )
  1057.     {
  1058.         DXTRACE_ERR_MSGBOX( TEXT("Duplicate"), hr );
  1059.         goto LCleanup;
  1060.     }
  1061.  
  1062.     if( FAILED( hr = pEnumHostsResponseMsg->pAddressDevice->Duplicate( &pDPHostEnum->pDeviceAddr ) ) )
  1063.     {
  1064.         DXTRACE_ERR_MSGBOX( TEXT("Duplicate"), hr );
  1065.         goto LCleanup;
  1066.     }
  1067.  
  1068.     // Deep copy the DPN_APPLICATION_DESC from
  1069.     pDPHostEnum->pAppDesc = new DPN_APPLICATION_DESC;
  1070.     if( NULL == pDPHostEnum->pAppDesc )
  1071.     {
  1072.         hr = E_OUTOFMEMORY;
  1073.         DXTRACE_ERR_MSGBOX( TEXT("SessionsDlgNoteEnumResponse"), hr );
  1074.         goto LCleanup;
  1075.     }
  1076.  
  1077.     ZeroMemory( pDPHostEnum->pAppDesc, sizeof(DPN_APPLICATION_DESC) );
  1078.     memcpy( pDPHostEnum->pAppDesc, pResponseMsgAppDesc, sizeof(DPN_APPLICATION_DESC) );
  1079.     if( pResponseMsgAppDesc->pwszSessionName )
  1080.     {
  1081.         pDPHostEnum->pAppDesc->pwszSessionName = new WCHAR[ wcslen(pResponseMsgAppDesc->pwszSessionName)+1 ];
  1082.         wcscpy( pDPHostEnum->pAppDesc->pwszSessionName,
  1083.                 pResponseMsgAppDesc->pwszSessionName );
  1084.     }
  1085.  
  1086.     // Update the time this was done, so that we can expire this host
  1087.     // if it doesn't refresh w/in a certain amount of time
  1088.     pDPHostEnum->dwLastPollTime = GETTIMESTAMP();
  1089.  
  1090.     // Check to see if the current number of players changed
  1091.     TCHAR szSessionTemp[MAX_PATH];
  1092.     if( pResponseMsgAppDesc->dwMaxPlayers > 0 )
  1093.     {
  1094.         _sntprintf( szSessionTemp, MAX_PATH-1, TEXT("%s (%d/%d) (%dms)"), strName,
  1095.                     pResponseMsgAppDesc->dwCurrentPlayers,
  1096.                     pResponseMsgAppDesc->dwMaxPlayers,
  1097.                     pEnumHostsResponseMsg->dwRoundTripLatencyMS );
  1098.  
  1099.         // Null terminate
  1100.         szSessionTemp[ MAX_PATH-1 ] = 0;
  1101.     }
  1102.     else
  1103.     {
  1104.         _sntprintf( szSessionTemp, MAX_PATH-1, TEXT("%s (%d) (%dms)"), strName,
  1105.                     pResponseMsgAppDesc->dwCurrentPlayers,
  1106.                     pEnumHostsResponseMsg->dwRoundTripLatencyMS );
  1107.  
  1108.         // Null terminate
  1109.         szSessionTemp[ MAX_PATH-1 ] = 0;
  1110.     }
  1111.  
  1112.     // if this node was previously invalidated, or the session name is now
  1113.     // different the session list in the dialog needs to be updated
  1114.     if( ( pDPHostEnum->bValid == FALSE ) ||
  1115.         ( _tcscmp( pDPHostEnum->szSession, szSessionTemp ) != 0 ) )
  1116.     {
  1117.         m_bEnumListChanged = TRUE;
  1118.     }
  1119.     _tcscpy( pDPHostEnum->szSession, szSessionTemp );
  1120.  
  1121.     // This host is now valid
  1122.     pDPHostEnum->bValid = TRUE;
  1123.  
  1124. LCleanup:
  1125.     LeaveCriticalSection( &m_csHostEnum );
  1126.  
  1127.     return hr;
  1128. }
  1129.  
  1130.  
  1131.  
  1132.  
  1133. //-----------------------------------------------------------------------------
  1134. // Name: SessionsDlgExpireOldHostEnums
  1135. // Desc: Check all nodes to see if any have expired yet.
  1136. //-----------------------------------------------------------------------------
  1137. VOID CNetConnectWizard::SessionsDlgExpireOldHostEnums()
  1138. {
  1139.     DWORD dwCurrentTime = GETTIMESTAMP();
  1140.  
  1141.     // This is called from the dialog UI thread, SessionsDlgNoteEnumResponse
  1142.     // is called from the DirectPlay message handler threads so
  1143.     // they may also be inside it at this time, so we need to go into the
  1144.     // critical section first
  1145.     EnterCriticalSection( &m_csHostEnum );
  1146.  
  1147.     DPHostEnumInfo* pDPHostEnum = m_DPHostEnumHead.pNext;
  1148.     while ( pDPHostEnum != &m_DPHostEnumHead )
  1149.     {
  1150.         // Check the poll time to expire stale entries.  Also check to see if
  1151.         // the entry is already invalid.  If so, don't note that the enum list
  1152.         // changed because that causes the list in the dialog to constantly redraw.
  1153.         if( ( pDPHostEnum->bValid != FALSE ) &&
  1154.             ( pDPHostEnum->dwLastPollTime < dwCurrentTime - m_dwEnumHostExpireInterval ) )
  1155.         {
  1156.             // This node has expired, so invalidate it.
  1157.             pDPHostEnum->bValid = FALSE;
  1158.             m_bEnumListChanged  = TRUE;
  1159.         }
  1160.  
  1161.         pDPHostEnum = pDPHostEnum->pNext;
  1162.     }
  1163.  
  1164.     LeaveCriticalSection( &m_csHostEnum );
  1165. }
  1166.  
  1167.  
  1168.  
  1169.  
  1170. //-----------------------------------------------------------------------------
  1171. // Name: SessionsDlgDisplayEnumList
  1172. // Desc: Display the list of hosts in the dialog box
  1173. //-----------------------------------------------------------------------------
  1174. HRESULT CNetConnectWizard::SessionsDlgDisplayEnumList( HWND hDlg )
  1175. {
  1176.     HWND           hWndListBox   = GetDlgItem( hDlg, IDC_GAMES_LIST );
  1177.     DPHostEnumInfo* pDPHostEnumSelected = NULL;
  1178.     GUID           guidSelectedInstance;
  1179.     BOOL           bFindSelectedGUID;
  1180.     BOOL           bFoundSelectedGUID;
  1181.     int            nItemSelected;
  1182.  
  1183.     // This is called from the dialog UI thread, SessionsDlgNoteEnumResponse
  1184.     // is called from the DirectPlay message handler threads so
  1185.     // they may also be inside it at this time, so we need to go into the
  1186.     // critical section first
  1187.     EnterCriticalSection( &m_csHostEnum );
  1188.  
  1189.     // Only update the display list if it has changed since last time
  1190.     if( !m_bEnumListChanged )
  1191.     {
  1192.         LeaveCriticalSection( &m_csHostEnum );
  1193.         return S_OK;
  1194.     }
  1195.  
  1196.     m_bEnumListChanged = FALSE;
  1197.  
  1198.     bFindSelectedGUID  = FALSE;
  1199.     bFoundSelectedGUID = FALSE;
  1200.  
  1201.     // Try to keep the same session selected unless it goes away or
  1202.     // there is no real session currently selected
  1203.     nItemSelected = (int)SendMessage( hWndListBox, LB_GETCURSEL, 0, 0 );
  1204.     if( nItemSelected != LB_ERR )
  1205.     {
  1206.         pDPHostEnumSelected = (DPHostEnumInfo*) SendMessage( hWndListBox, LB_GETITEMDATA,
  1207.                                                              nItemSelected, 0 );
  1208.         if( pDPHostEnumSelected != NULL && pDPHostEnumSelected->bValid )
  1209.         {
  1210.             guidSelectedInstance = pDPHostEnumSelected->pAppDesc->guidInstance;
  1211.             bFindSelectedGUID = TRUE;
  1212.         }
  1213.     }
  1214.  
  1215.     // Tell listbox not to redraw itself since the contents are going to change
  1216.     SendMessage( hWndListBox, WM_SETREDRAW, FALSE, 0 );
  1217.  
  1218.     // Test to see if any sessions exist in the linked list
  1219.     DPHostEnumInfo* pDPHostEnum = m_DPHostEnumHead.pNext;
  1220.     while ( pDPHostEnum != &m_DPHostEnumHead )
  1221.     {
  1222.         if( pDPHostEnum->bValid )
  1223.             break;
  1224.         pDPHostEnum = pDPHostEnum->pNext;
  1225.     }
  1226.  
  1227.     // If there are any sessions in list,
  1228.     // then add them to the listbox
  1229.     if( pDPHostEnum != &m_DPHostEnumHead )
  1230.     {
  1231.         // Clear the contents from the list box and enable the join button
  1232.         SendMessage( hWndListBox, LB_RESETCONTENT, 0, 0 );
  1233.  
  1234.         // Enable the join button only if not already connecting to a game
  1235.         if( !m_bConnecting )
  1236.             EnableWindow( GetDlgItem( hDlg, IDC_JOIN ), TRUE );
  1237.  
  1238.         pDPHostEnum = m_DPHostEnumHead.pNext;
  1239.         while ( pDPHostEnum != &m_DPHostEnumHead )
  1240.         {
  1241.             // Add host to list box if it is valid
  1242.             if( pDPHostEnum->bValid )
  1243.             {
  1244.                 int nIndex = (int)SendMessage( hWndListBox, LB_ADDSTRING, 0,
  1245.                                                (LPARAM)pDPHostEnum->szSession );
  1246.                 SendMessage( hWndListBox, LB_SETITEMDATA, nIndex, (LPARAM)pDPHostEnum );
  1247.  
  1248.                 if( bFindSelectedGUID )
  1249.                 {
  1250.                     // Look for the session the was selected before
  1251.                     if( pDPHostEnum->pAppDesc->guidInstance == guidSelectedInstance )
  1252.                     {
  1253.                         SendMessage( hWndListBox, LB_SETCURSEL, nIndex, 0 );
  1254.                         bFoundSelectedGUID = TRUE;
  1255.                     }
  1256.                 }
  1257.             }
  1258.  
  1259.             pDPHostEnum = pDPHostEnum->pNext;
  1260.         }
  1261.  
  1262.         if( !bFindSelectedGUID || !bFoundSelectedGUID )
  1263.             SendMessage( hWndListBox, LB_SETCURSEL, 0, 0 );
  1264.     }
  1265.     else
  1266.     {
  1267.         // There are no active session, so just reset the listbox
  1268.         SessionsDlgInitListbox( hDlg );
  1269.     }
  1270.  
  1271.     // Tell listbox to redraw itself now since the contents have changed
  1272.     SendMessage( hWndListBox, WM_SETREDRAW, TRUE, 0 );
  1273.     InvalidateRect( hWndListBox, NULL, FALSE );
  1274.  
  1275.     LeaveCriticalSection( &m_csHostEnum );
  1276.  
  1277.     return S_OK;
  1278. }
  1279.  
  1280.  
  1281.  
  1282.  
  1283. //-----------------------------------------------------------------------------
  1284. // Name: SessionsDlgJoinGame()
  1285. // Desc: Joins the selected DirectPlay session
  1286. //-----------------------------------------------------------------------------
  1287. HRESULT CNetConnectWizard::SessionsDlgJoinGame( HWND hDlg )
  1288. {
  1289.     HRESULT         hr;
  1290.     HWND            hWndListBox = GetDlgItem( hDlg, IDC_GAMES_LIST );
  1291.     DPHostEnumInfo* pDPHostEnumSelected = NULL;
  1292.     int             nItemSelected;
  1293.  
  1294.     m_bHostPlayer = FALSE;
  1295.  
  1296.     // Add status text in list box
  1297.     nItemSelected = (int)SendMessage( hWndListBox, LB_GETCURSEL, 0, 0 );
  1298.  
  1299.     EnterCriticalSection( &m_csHostEnum );
  1300.  
  1301.     pDPHostEnumSelected = (DPHostEnumInfo*) SendMessage( hWndListBox, LB_GETITEMDATA,
  1302.                                                          nItemSelected, 0 );
  1303.  
  1304.     if( NULL == pDPHostEnumSelected )
  1305.     {
  1306.         MessageBox( hDlg, TEXT("There are no games to join."),
  1307.                     TEXT("DirectPlay Sample"), MB_OK );
  1308.         hr = S_OK;
  1309.         goto LCleanReturn;
  1310.     }
  1311.  
  1312.     m_bConnecting = TRUE;
  1313.  
  1314.     // Set the peer info
  1315.     WCHAR wszPeerName[MAX_PATH];
  1316.     DXUtil_ConvertGenericStringToWideCch( wszPeerName, m_strLocalPlayerName, MAX_PATH );
  1317.  
  1318.     DPN_PLAYER_INFO dpPlayerInfo;
  1319.     ZeroMemory( &dpPlayerInfo, sizeof(DPN_PLAYER_INFO) );
  1320.     dpPlayerInfo.dwSize = sizeof(DPN_PLAYER_INFO);
  1321.     dpPlayerInfo.dwInfoFlags = DPNINFO_NAME;
  1322.     dpPlayerInfo.pwszName = wszPeerName;
  1323.  
  1324.     // Set the peer info, and use the DPNOP_SYNC since by default this
  1325.     // is an async call.  If it is not DPNOP_SYNC, then the peer info may not
  1326.     // be set by the time we call Connect() below.
  1327.     if( FAILED( hr = m_pDP->SetPeerInfo( &dpPlayerInfo, NULL, NULL, DPNOP_SYNC ) ) )
  1328.     {
  1329.         DXTRACE_ERR_MSGBOX( TEXT("SetPeerInfo"), hr );
  1330.         goto LCleanReturn;
  1331.     }
  1332.  
  1333.     ResetEvent( m_hConnectCompleteEvent );
  1334.  
  1335.     // Connect to an existing session. DPNCONNECT_OKTOQUERYFORADDRESSING allows
  1336.     // DirectPlay to prompt the user using a dialog box for any device address
  1337.     // or host address information that is missing
  1338.     // We also pass in copies of the app desc and host addr, since pDPHostEnumSelected
  1339.     // might be deleted from another thread that calls SessionsDlgExpireOldHostEnums().
  1340.     // This process could also be done using reference counting instead.
  1341.     hr = m_pDP->Connect( pDPHostEnumSelected->pAppDesc,       // the application desc
  1342.                          pDPHostEnumSelected->pHostAddr,      // address of the host of the session
  1343.                          pDPHostEnumSelected->pDeviceAddr,    // address of the local device the enum responses were received on
  1344.                          NULL, NULL,                          // DPN_SECURITY_DESC, DPN_SECURITY_CREDENTIALS
  1345.                          NULL, 0,                             // user data, user data size
  1346.                          NULL,                                // player context,
  1347.                          NULL, &m_hConnectAsyncOp,            // async context, async handle,
  1348.                          DPNCONNECT_OKTOQUERYFORADDRESSING ); // flags
  1349.     if( FAILED(hr) && hr != E_PENDING )
  1350.     {
  1351.         DXTRACE_ERR_MSGBOX( TEXT("Connect"), hr );
  1352.         goto LCleanReturn;
  1353.     }
  1354.  
  1355.     // Set a timer to wait for m_hConnectCompleteEvent to be signaled.
  1356.     // This will tell us when DPN_MSGID_CONNECT_COMPLETE has been processed
  1357.     // which lets us know if the connect was successful or not.
  1358.     SetTimer( hDlg, TIMERID_CONNECT_COMPLETE, 100, NULL );
  1359.  
  1360.     // Disable the create/join buttons until connect succeeds or fails
  1361.     EnableWindow( GetDlgItem( hDlg, IDC_JOIN ), FALSE );
  1362.     EnableWindow( GetDlgItem( hDlg, IDC_CREATE ), FALSE );
  1363.  
  1364.     hr = S_OK;
  1365.  
  1366. LCleanReturn:
  1367.     LeaveCriticalSection( &m_csHostEnum );
  1368.  
  1369.     return hr;
  1370. }
  1371.  
  1372.  
  1373.  
  1374.  
  1375. //-----------------------------------------------------------------------------
  1376. // Name: SessionsDlgCreateGame()
  1377. // Desc: Asks the user the session name, and creates a new DirectPlay session
  1378. //-----------------------------------------------------------------------------
  1379. HRESULT CNetConnectWizard::SessionsDlgCreateGame( HWND hDlg )
  1380. {
  1381.     HRESULT hr = S_OK;
  1382.     int     nResult;
  1383.  
  1384.     // Display a modal multiplayer connect dialog box.
  1385.     EnableWindow( hDlg, FALSE );
  1386.     nResult = (int)DialogBox( m_hInst, MAKEINTRESOURCE(IDD_MULTIPLAYER_CREATE),
  1387.                               hDlg, (DLGPROC) StaticCreateSessionDlgProc );
  1388.     EnableWindow( hDlg, TRUE );
  1389.  
  1390.     if( nResult == IDCANCEL )
  1391.         return S_OK;
  1392.  
  1393.     // Stop the search if we are about to connect
  1394.     if( m_bSearchingForSessions )
  1395.     {
  1396.         CheckDlgButton( m_hDlg, IDC_SEARCH_CHECK, BST_UNCHECKED );
  1397.         SendMessage( m_hDlg, WM_COMMAND, IDC_SEARCH_CHECK, 0 );
  1398.     }
  1399.  
  1400.     m_bHostPlayer = TRUE;
  1401.  
  1402.     IDirectPlay8Address*   pDP8AddressHost  = NULL;
  1403.     WCHAR*                 wszHostName      = NULL;
  1404.  
  1405.     // Create the local host address object
  1406.     if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay8Address, NULL, 
  1407.                                        CLSCTX_ALL, IID_IDirectPlay8Address,
  1408.                                        (LPVOID*) &pDP8AddressHost ) ) )
  1409.     {
  1410.         DXTRACE_ERR_MSGBOX( TEXT("CoCreateInstance"), hr );
  1411.         goto LCleanup;
  1412.     }
  1413.  
  1414.     // Set service provider
  1415.     if( FAILED( hr = pDP8AddressHost->SetSP( &m_guidSP ) ) )
  1416.     {
  1417.         DXTRACE_ERR_MSGBOX( TEXT("SetSP"), hr );
  1418.         goto LCleanup;
  1419.     }
  1420.  
  1421.     // If were are using a service provider that requires a port value, 
  1422.     // and the user has requested a particular port number, set that
  1423.     // port as a component of the host address. If no port is specified, 
  1424.     // DirectPlay will automatically select an open port
  1425.     if( m_dwPort != 0 && SPRequiresPort( &m_guidSP ) )
  1426.     {
  1427.         hr = pDP8AddressHost->AddComponent( DPNA_KEY_PORT, 
  1428.                                             &m_dwPort, 
  1429.                                             sizeof(m_dwPort),
  1430.                                             DPNA_DATATYPE_DWORD );
  1431.         if( FAILED(hr) )
  1432.         {
  1433.             DXTRACE_ERR_MSGBOX( TEXT("AddComponent"), hr );
  1434.             goto LCleanup;
  1435.         }
  1436.     }
  1437.  
  1438.     // Set peer info name
  1439.     WCHAR wszPeerName[MAX_PATH];
  1440.     DXUtil_ConvertGenericStringToWideCch( wszPeerName, m_strLocalPlayerName, MAX_PATH );
  1441.  
  1442.     DPN_PLAYER_INFO dpPlayerInfo;
  1443.     ZeroMemory( &dpPlayerInfo, sizeof(DPN_PLAYER_INFO) );
  1444.     dpPlayerInfo.dwSize = sizeof(DPN_PLAYER_INFO);
  1445.     dpPlayerInfo.dwInfoFlags = DPNINFO_NAME;
  1446.     dpPlayerInfo.pwszName = wszPeerName;
  1447.  
  1448.     // Set the peer info, and use the DPNOP_SYNC since by default this
  1449.     // is an async call.  If it is not DPNOP_SYNC, then the peer info may not
  1450.     // be set by the time we call Host() below.
  1451.     if( FAILED( hr = m_pDP->SetPeerInfo( &dpPlayerInfo, NULL, NULL, DPNOP_SYNC ) ) )
  1452.     {
  1453.         DXTRACE_ERR_MSGBOX( TEXT("SetPeerInfo"), hr );
  1454.         goto LCleanup;
  1455.     }
  1456.  
  1457.     WCHAR wszSessionName[MAX_PATH];
  1458.     DXUtil_ConvertGenericStringToWideCch( wszSessionName, m_strSessionName, MAX_PATH );
  1459.  
  1460.     // Setup the application desc
  1461.     DPN_APPLICATION_DESC dnAppDesc;
  1462.     ZeroMemory( &dnAppDesc, sizeof(DPN_APPLICATION_DESC) );
  1463.     dnAppDesc.dwSize          = sizeof(DPN_APPLICATION_DESC);
  1464.     dnAppDesc.guidApplication = m_guidApp;
  1465.     dnAppDesc.pwszSessionName = wszSessionName;
  1466.     dnAppDesc.dwMaxPlayers    = m_dwMaxPlayers;
  1467.     dnAppDesc.dwFlags         = 0;
  1468.     if( m_bMigrateHost )
  1469.         dnAppDesc.dwFlags |= DPNSESSION_MIGRATE_HOST;
  1470.  
  1471.     if( !m_bUseDPNSVR )
  1472.         dnAppDesc.dwFlags |= DPNSESSION_NODPNSVR;
  1473.  
  1474.     if( SIGN_FAST == m_eSigningType )
  1475.         dnAppDesc.dwFlags |= DPNSESSION_FAST_SIGNED;
  1476.     else if( SIGN_FULL == m_eSigningType )
  1477.         dnAppDesc.dwFlags |= DPNSESSION_FULL_SIGNED;
  1478.  
  1479.     
  1480.     // Host a game on m_pDeviceAddress as described by dnAppDesc
  1481.     // DPNHOST_OKTOQUERYFORADDRESSING allows DirectPlay to prompt the user
  1482.     // using a dialog box for any device address information that is missing
  1483.     if( FAILED( hr = m_pDP->Host( &dnAppDesc,               // the application desc
  1484.                                   &pDP8AddressHost,         // array of addresses of the local devices used to connect to the host
  1485.                                   1,                        // number in array
  1486.                                   NULL, NULL,               // DPN_SECURITY_DESC, DPN_SECURITY_CREDENTIALS
  1487.                                   NULL,                     // player context
  1488.                                   DPNHOST_OKTOQUERYFORADDRESSING ) ) ) // flags
  1489.     { 
  1490.         // This error is often caused by a port conflict
  1491.         if( hr == DPNERR_INVALIDDEVICEADDRESS && 
  1492.             m_dwPort != 0 && SPRequiresPort( &m_guidSP ) )
  1493.         {
  1494.             MessageBox( hDlg, TEXT("This error is often caused by a port conflict.\n\n")
  1495.                               TEXT("If another application is already using the port you specified,\n")
  1496.                               TEXT("try creating the game using a different port number."),
  1497.                         TEXT("Invalid Device Address"), MB_OK | MB_ICONINFORMATION );
  1498.         }
  1499.  
  1500.         DXTRACE_ERR_MSGBOX( TEXT("Host"), hr );
  1501.         goto LCleanup;
  1502.     }
  1503.  
  1504.     // DirectPlay connect successful, so end dialog
  1505.     m_hrDialog = NCW_S_FORWARD;
  1506.     EndDialog( hDlg, 0 );
  1507.  
  1508. LCleanup:
  1509.     SAFE_RELEASE( pDP8AddressHost );
  1510.     SAFE_DELETE( wszHostName );
  1511.  
  1512.     return hr;
  1513. }
  1514.  
  1515.  
  1516.  
  1517.  
  1518. //-----------------------------------------------------------------------------
  1519. // Name: StaticConnectionsDlgProc()
  1520. // Desc: Static msg handler which passes messages
  1521. //-----------------------------------------------------------------------------
  1522. INT_PTR CALLBACK CNetConnectWizard::StaticCreateSessionDlgProc( HWND hDlg, UINT uMsg,
  1523.                                                                 WPARAM wParam, LPARAM lParam )
  1524. {
  1525.     if( g_pNCW )
  1526.         return g_pNCW->CreateSessionDlgProc( hDlg, uMsg, wParam, lParam );
  1527.  
  1528.     return FALSE; // Message not handled
  1529. }
  1530.  
  1531.  
  1532.  
  1533.  
  1534. //-----------------------------------------------------------------------------
  1535. // Name: CreateSessionDlgProc()
  1536. // Desc: Handles messages fro the multiplayer create game dialog
  1537. //-----------------------------------------------------------------------------
  1538. INT_PTR CALLBACK CNetConnectWizard::CreateSessionDlgProc( HWND hDlg, UINT msg,
  1539.                                                           WPARAM wParam, LPARAM lParam )
  1540. {
  1541.     UNREFERENCED_PARAMETER( lParam );
  1542.     DWORD dwNameLength;
  1543.  
  1544.     switch( msg )
  1545.     {
  1546.         case WM_INITDIALOG:
  1547. #if defined(WIN32_PLATFORM_PSPC) && (_WIN32_WCE >= 300)
  1548.             SHINITDLGINFO   shidi;
  1549.             memset(&shidi, 0, sizeof(SHINITDLGINFO));
  1550.             shidi.dwMask = SHIDIM_FLAGS;
  1551.             shidi.dwFlags = SHIDIF_SIPDOWN | SHIDIF_SIZEDLGFULLSCREEN;
  1552.             shidi.hDlg = hDlg;
  1553.  
  1554.             SetForegroundWindow(hDlg);
  1555.             SHInitDialog(&shidi);
  1556. #endif // WIN32_PLATFORM_PSPC
  1557.  
  1558.             SetDlgItemText( hDlg, IDC_EDIT_SESSION_NAME, m_strSessionName );
  1559.             CheckDlgButton( hDlg, IDC_MIGRATE_HOST, BST_CHECKED );
  1560.             CheckDlgButton( hDlg, IDC_SIGNING_FAST, BST_CHECKED );
  1561.  
  1562.             // Fill in the port value if the calling application gave us a default
  1563.             if( m_dwPort != 0 )
  1564.             {
  1565.                 TCHAR strPort[40];
  1566.                 _itot( m_dwPort, strPort, 10 );
  1567.                 SetDlgItemText( hDlg, IDC_LOCAL_PORT, strPort );
  1568.             }
  1569.  
  1570.             // Hide the port field for service providers which don't use it
  1571.             if( !SPRequiresPort( &m_guidSP ) )
  1572.             {
  1573.                 ShowWindow( GetDlgItem( hDlg, IDC_LOCAL_PORT ), SW_HIDE );
  1574.                 ShowWindow( GetDlgItem( hDlg, IDC_LOCAL_PORT_TEXT ), SW_HIDE );
  1575.             }
  1576.             
  1577.             return TRUE;
  1578.  
  1579. // Context-sensitive help is not supported on PocketPC
  1580. #ifndef UNDER_CE
  1581.         case WM_HELP:
  1582.             LPHELPINFO lphi;
  1583.             lphi = (LPHELPINFO) lParam;
  1584.  
  1585.             switch( lphi->iCtrlId )
  1586.             {
  1587.                 case IDC_EDIT_SESSION_NAME:
  1588.                     MessageBox( hDlg, TEXT("The name used to help other players identify\n")
  1589.                                       TEXT("your session across the network."), 
  1590.                                 TEXT("Game Name"), MB_OK | MB_ICONQUESTION );
  1591.                     break;
  1592.                 
  1593.                 case IDC_SIGNING_FULL:
  1594.                 case IDC_SIGNING_FAST:
  1595.                     MessageBox( hDlg, TEXT("The level of cryptographic security to use for\n")
  1596.                                       TEXT("network data; full-signing provides the most\n")
  1597.                                       TEXT("protection against spoofing at the cost of\n")
  1598.                                       TEXT("additional packet size."), 
  1599.                                 TEXT("Session Signing"), MB_OK | MB_ICONQUESTION );
  1600.                     break;
  1601.  
  1602.                 case IDC_MIGRATE_HOST:
  1603.                     MessageBox( hDlg, TEXT("If enabled, DirectPlay will automatically select\n")
  1604.                                       TEXT("a new session host if the current host exits."), 
  1605.                                 TEXT("Host Migration"), MB_OK | MB_ICONQUESTION );
  1606.                     break;
  1607.  
  1608.                 case IDC_USE_DPNSVR:
  1609.                     MessageBox( hDlg, TEXT("This DirectPlay-managed application accepts\n")
  1610.                                       TEXT("enumeration requests on a known port and forwards\n")
  1611.                                       TEXT("incoming requests to all sessions on the machine,\n")
  1612.                                       TEXT("which allows the querying player to find sessions\n")
  1613.                                       TEXT("without knowing the port address.\n\n")
  1614.                                       TEXT("This service may not work properly with certain\n")
  1615.                                       TEXT("NAT configurations."), 
  1616.                                 TEXT("DPNSVR"), MB_OK | MB_ICONQUESTION );
  1617.                     break;
  1618.  
  1619.                 case IDC_LOCAL_PORT:
  1620.                     MessageBox( hDlg, TEXT("Specifies the local port on which to host the new\n")
  1621.                                       TEXT("session. If set blank, DirectPlay will automatically\n")
  1622.                                       TEXT("select an open port."), 
  1623.                                 TEXT("Local Port"), MB_OK | MB_ICONQUESTION );
  1624.                     break;
  1625.  
  1626.                 default:
  1627.                     return FALSE; // Not handled
  1628.             }
  1629.             return TRUE;
  1630. #endif // !UNDER_CE
  1631.  
  1632.         case WM_COMMAND:
  1633.             switch( LOWORD(wParam) )
  1634.             {
  1635.                 case IDOK:
  1636.                     dwNameLength = GetDlgItemText( hDlg, IDC_EDIT_SESSION_NAME,
  1637.                                                    m_strSessionName,
  1638.                                                    MAX_PATH );
  1639.                     if( dwNameLength == 0 )
  1640.                         return TRUE; // Don't accept blank session names
  1641.  
  1642.                     m_bMigrateHost = ( IsDlgButtonChecked( hDlg,
  1643.                                        IDC_MIGRATE_HOST ) == BST_CHECKED );
  1644.  
  1645.                     m_bUseDPNSVR = ( IsDlgButtonChecked( hDlg,
  1646.                                      IDC_USE_DPNSVR ) == BST_CHECKED );
  1647.  
  1648.                     // Set the desired port value
  1649.                     TCHAR strPort[40];
  1650.                     GetDlgItemText( hDlg, IDC_LOCAL_PORT, strPort, 40 );
  1651.                     strPort[39] = 0;
  1652.  
  1653.                     m_dwPort = _ttoi( strPort );
  1654.  
  1655.                     // Set session signing options
  1656.                     if( BST_CHECKED == IsDlgButtonChecked( hDlg, IDC_SIGNING_FAST ) )
  1657.                         m_eSigningType = SIGN_FAST;
  1658.                     else if( BST_CHECKED == IsDlgButtonChecked( hDlg, IDC_SIGNING_FULL ) )
  1659.                         m_eSigningType = SIGN_FULL;
  1660.                     else
  1661.                         m_eSigningType = SIGN_NONE;
  1662.  
  1663.                     EndDialog( hDlg, IDOK );
  1664.                     return TRUE;
  1665.  
  1666.                 case IDCANCEL:
  1667.                     EndDialog( hDlg, IDCANCEL );
  1668.                     return TRUE;
  1669.             }
  1670.             break;
  1671.     }
  1672.  
  1673.     return FALSE; // Didn't handle message
  1674. }
  1675.  
  1676.  
  1677.  
  1678.  
  1679. //-----------------------------------------------------------------------------
  1680. // Name: SessionsDlgEnumListCleanup()
  1681. // Desc: Deletes the linked list, g_DPHostEnumInfoHead
  1682. //-----------------------------------------------------------------------------
  1683. VOID CNetConnectWizard::SessionsDlgEnumListCleanup()
  1684. {
  1685.     DPHostEnumInfo* pDPHostEnum = m_DPHostEnumHead.pNext;
  1686.     DPHostEnumInfo* pDPHostEnumDelete;
  1687.  
  1688.     while ( pDPHostEnum != &m_DPHostEnumHead )
  1689.     {
  1690.         pDPHostEnumDelete = pDPHostEnum;
  1691.         pDPHostEnum = pDPHostEnum->pNext;
  1692.  
  1693.         if( pDPHostEnumDelete->pAppDesc )
  1694.         {
  1695.             SAFE_DELETE_ARRAY( pDPHostEnumDelete->pAppDesc->pwszSessionName );
  1696.             SAFE_DELETE( pDPHostEnumDelete->pAppDesc );
  1697.         }
  1698.  
  1699.         // Changed from array delete to Release
  1700.         SAFE_RELEASE( pDPHostEnumDelete->pHostAddr );
  1701.         SAFE_RELEASE( pDPHostEnumDelete->pDeviceAddr );
  1702.         SAFE_DELETE( pDPHostEnumDelete );
  1703.     }
  1704.  
  1705.     // Re-link the g_DPHostEnumInfoHead circular linked list
  1706.     m_DPHostEnumHead.pNext = &m_DPHostEnumHead;
  1707. }
  1708.  
  1709.  
  1710.  
  1711.  
  1712. //-----------------------------------------------------------------------------
  1713. // Name: StaticAddressDlgProc()
  1714. // Desc: Static msg handler which passes messages
  1715. //-----------------------------------------------------------------------------
  1716. INT_PTR CALLBACK CNetConnectWizard::StaticAddressDlgProc( HWND hDlg, UINT uMsg,
  1717.                                                           WPARAM wParam, LPARAM lParam )
  1718. {
  1719.     if( g_pNCW )
  1720.         return g_pNCW->AddressDlgProc( hDlg, uMsg, wParam, lParam );
  1721.  
  1722.     return FALSE; // Message not handled
  1723. }
  1724.  
  1725.  
  1726.  
  1727.  
  1728. //-----------------------------------------------------------------------------
  1729. // Name: AddressDlgProc()
  1730. // Desc: Handles messages for the multiplayer connect dialog
  1731. //-----------------------------------------------------------------------------
  1732. INT_PTR CALLBACK CNetConnectWizard::AddressDlgProc( HWND hDlg, UINT msg,
  1733.                                                     WPARAM wParam, LPARAM lParam )
  1734. {
  1735.     UNREFERENCED_PARAMETER( lParam );
  1736.     
  1737.     switch( msg )
  1738.     {
  1739.         case WM_INITDIALOG:
  1740.         {
  1741. #if defined(WIN32_PLATFORM_PSPC) && (_WIN32_WCE >= 300)
  1742.             SHINITDLGINFO   shidi;
  1743.             memset(&shidi, 0, sizeof(SHINITDLGINFO));
  1744.             shidi.dwMask = SHIDIM_FLAGS;
  1745.             shidi.dwFlags = SHIDIF_SIPDOWN | SHIDIF_SIZEDLGFULLSCREEN;
  1746.             shidi.hDlg = hDlg;
  1747.  
  1748.             SetForegroundWindow(hDlg);
  1749.             SHInitDialog(&shidi);
  1750. #endif // WIN32_PLATFORM_PSPC
  1751.  
  1752.             // Set the default port
  1753.             if( m_dwPort != 0 )
  1754.             {
  1755.                 TCHAR strPort[40];
  1756.                 _itot( m_dwPort, strPort, 10 );
  1757.                 SetDlgItemText( hDlg, IDC_REMOTE_PORT, strPort );
  1758.             }
  1759.  
  1760.             return TRUE;
  1761.         }
  1762.  
  1763.         case WM_COMMAND:
  1764.         {
  1765.             switch( LOWORD(wParam) )
  1766.             {
  1767.                 case IDOK:
  1768.                     // Store the user's choices
  1769.                     TCHAR strPort[40];
  1770.                     GetDlgItemText( hDlg, IDC_REMOTE_PORT, strPort, 40 );
  1771.                     strPort[39] = 0;
  1772.                     m_dwPort = _ttoi( strPort );
  1773.  
  1774.                     GetDlgItemText( hDlg, IDC_REMOTE_HOSTNAME, m_strHostname, MAX_PATH );
  1775.                     m_strHostname[MAX_PATH-1] = 0;
  1776.  
  1777.                     EndDialog( hDlg, IDOK );
  1778.                     return TRUE;
  1779.  
  1780.                 case IDCANCEL:
  1781.                     EndDialog( hDlg, IDCANCEL );
  1782.                     return TRUE;
  1783.             }
  1784.             break;
  1785.         }
  1786.     }
  1787.  
  1788.     return FALSE; // Not handled
  1789. }
  1790.  
  1791.  
  1792.  
  1793.  
  1794. //-----------------------------------------------------------------------------
  1795. // Name: MessageHandler
  1796. // Desc: Handler for DirectPlay messages.  This function is called by
  1797. //       the DirectPlay message handler pool of threads, so be careful of thread
  1798. //       synchronization problems with shared memory
  1799. //-----------------------------------------------------------------------------
  1800. HRESULT WINAPI CNetConnectWizard::MessageHandler( PVOID pvUserContext,
  1801.                                                   DWORD dwMessageId,
  1802.                                                   PVOID pMsgBuffer )
  1803. {
  1804.     UNREFERENCED_PARAMETER( pvUserContext );
  1805.     
  1806.     // Try not to stay in this message handler for too long, otherwise
  1807.     // there will be a backlog of data.  The best solution is to
  1808.     // queue data as it comes in, and then handle it on other threads.
  1809.  
  1810.     // This function is called by the DirectPlay message handler pool of
  1811.     // threads, so be careful of thread synchronization problems with shared memory
  1812.  
  1813.     switch(dwMessageId)
  1814.     {
  1815.         case DPN_MSGID_ENUM_HOSTS_RESPONSE:
  1816.         {
  1817.             PDPNMSG_ENUM_HOSTS_RESPONSE pEnumHostsResponseMsg;
  1818.             pEnumHostsResponseMsg = (PDPNMSG_ENUM_HOSTS_RESPONSE)pMsgBuffer;
  1819.  
  1820.             // Take note of the host response
  1821.             SessionsDlgNoteEnumResponse( pEnumHostsResponseMsg );
  1822.             break;
  1823.         }
  1824.  
  1825.         case DPN_MSGID_ASYNC_OP_COMPLETE:
  1826.         {
  1827.             PDPNMSG_ASYNC_OP_COMPLETE pAsyncOpCompleteMsg;
  1828.             pAsyncOpCompleteMsg = (PDPNMSG_ASYNC_OP_COMPLETE)pMsgBuffer;
  1829.  
  1830.             if( pAsyncOpCompleteMsg->hAsyncOp == m_hEnumAsyncOp )
  1831.                 SessionsDlgFinalizeEnumHosts( m_hDlg );
  1832.  
  1833.             break;
  1834.         }
  1835.  
  1836.         case DPN_MSGID_CONNECT_COMPLETE:
  1837.         {
  1838.             PDPNMSG_CONNECT_COMPLETE pConnectCompleteMsg;
  1839.             pConnectCompleteMsg = (PDPNMSG_CONNECT_COMPLETE)pMsgBuffer;
  1840.  
  1841.             // Set m_hrConnectComplete, then set an event letting
  1842.             // everyone know that the DPN_MSGID_CONNECT_COMPLETE msg
  1843.             // has been handled
  1844.             m_hrConnectComplete = pConnectCompleteMsg->hResultCode;
  1845.             SetEvent( m_hConnectCompleteEvent );
  1846.             break;
  1847.         }
  1848.     }
  1849.  
  1850.     return S_OK;
  1851. }
  1852.  
  1853.  
  1854.  
  1855.  
  1856. //-----------------------------------------------------------------------------
  1857. // Name: ConnectUsingLobbySettings
  1858. // Desc: Call this after the DPL_MSGID_CONNECT has been processed to carry out
  1859. //       the connection settings received by the lobby client.  DPL_MSGID_CONNECT
  1860. //       will have already been processed if we were lobby launched, or after
  1861. //       WaitForConnection returns without timing out.
  1862. //-----------------------------------------------------------------------------
  1863. HRESULT CNetConnectWizard::ConnectUsingLobbySettings()
  1864. {
  1865.     HRESULT hr;
  1866.     DPNHANDLE hAsync;
  1867.  
  1868.     if( m_hLobbyClient == NULL )
  1869.         return E_INVALIDARG;
  1870.  
  1871.     DPL_CONNECTION_SETTINGS* pSettings = NULL;
  1872.     DWORD dwSettingsSize = 0;
  1873.  
  1874.     // Get the connection settings from the lobby.
  1875.     hr = m_pLobbiedApp->GetConnectionSettings( m_hLobbyClient, pSettings, &dwSettingsSize, 0 );
  1876.     if( hr != DPNERR_BUFFERTOOSMALL )
  1877.     {
  1878.         DXTRACE_ERR_MSGBOX( TEXT("GetConnectionSettings"), hr );
  1879.         goto LCleanReturn;
  1880.     }
  1881.  
  1882.     pSettings = (DPL_CONNECTION_SETTINGS*) new BYTE[dwSettingsSize];
  1883.     if( NULL == pSettings )
  1884.     {
  1885.         hr = E_OUTOFMEMORY;
  1886.         DXTRACE_ERR_MSGBOX( TEXT("ConnectUsingLobbySettings"), hr );
  1887.         goto LCleanReturn;
  1888.     }
  1889.  
  1890.     if( FAILED( hr = m_pLobbiedApp->GetConnectionSettings( m_hLobbyClient, pSettings, &dwSettingsSize, 0 ) ) )
  1891.     {
  1892.         DXTRACE_ERR_MSGBOX( TEXT("GetConnectionSettings"), hr );
  1893.         goto LCleanReturn;
  1894.     }
  1895.  
  1896.     // Check if the lobby told us to host the game
  1897.     m_bHostPlayer = (pSettings->dwFlags & DPLCONNECTSETTINGS_HOST);
  1898.  
  1899.     // Set the peer info
  1900.     WCHAR wszPeerName[MAX_PATH];
  1901.     DXUtil_ConvertGenericStringToWideCch( wszPeerName, m_strLocalPlayerName, MAX_PATH );
  1902.     DPN_PLAYER_INFO dpPlayerInfo;
  1903.     ZeroMemory( &dpPlayerInfo, sizeof(DPN_PLAYER_INFO) );
  1904.     dpPlayerInfo.dwSize = sizeof(DPN_PLAYER_INFO);
  1905.     dpPlayerInfo.dwInfoFlags = DPNINFO_NAME;
  1906.     dpPlayerInfo.pwszName = wszPeerName;
  1907.  
  1908.     // Set the peer info, and use the DPNOP_SYNC since by default this
  1909.     // is an async call.  If it is not DPNOP_SYNC, then the peer info may not
  1910.     // be set by the time we call Connect() below.
  1911.     if( FAILED( hr = m_pDP->SetPeerInfo( &dpPlayerInfo, NULL, NULL, DPNOP_SYNC ) ) )
  1912.     {
  1913.         DXTRACE_ERR_MSGBOX( TEXT("SetPeerInfo"), hr );
  1914.         goto LCleanReturn;
  1915.     }
  1916.  
  1917.     if( m_bHostPlayer )
  1918.     {
  1919.         // Enable host migrate by default.
  1920.         pSettings->dpnAppDesc.dwFlags |= DPNSESSION_MIGRATE_HOST;
  1921.  
  1922.         // Disable DPNSVR by default
  1923.         pSettings->dpnAppDesc.dwFlags |= DPNSESSION_NODPNSVR;
  1924.  
  1925.         // Host a game as described by pSettings
  1926.         if( FAILED( hr = m_pDP->Host( &pSettings->dpnAppDesc,               // the application desc
  1927.                                       pSettings->ppdp8DeviceAddresses,      // array of addresses of the local devices used to connect to the host
  1928.                                       pSettings->cNumDeviceAddresses,       // number in array
  1929.                                       NULL, NULL,                           // DPN_SECURITY_DESC, DPN_SECURITY_CREDENTIALS
  1930.                                       NULL,                                 // player context
  1931.                                       0 ) ) )                               // flags
  1932.         {
  1933.             DXTRACE_ERR_MSGBOX( TEXT("Host"), hr );
  1934.             goto LCleanReturn;
  1935.         }
  1936.     }
  1937.     else
  1938.     {
  1939.         // Connect to an existing session. There should only be on device address in
  1940.         // the connection settings structure when connecting to a session, so just
  1941.         // pass in the first one.
  1942.         // The enumeration is automatically cancelled after Connect is called 
  1943.         hr = m_pDP->Connect( &pSettings->dpnAppDesc,              // the application desc
  1944.                              pSettings->pdp8HostAddress,          // address of the host of the session
  1945.                              pSettings->ppdp8DeviceAddresses[0],  // address of the local device used to connect to the host
  1946.                              NULL, NULL,                          // DPN_SECURITY_DESC, DPN_SECURITY_CREDENTIALS
  1947.                              NULL, 0,                             // user data, user data size
  1948.                              NULL,                                // player context,
  1949.                              NULL, &hAsync,                       // async context, async handle,
  1950.                              0 );                                 // flags
  1951.         if( hr != E_PENDING && FAILED(hr) )
  1952.         {
  1953.             DXTRACE_ERR_MSGBOX( TEXT("Connect"), hr );
  1954.             goto LCleanReturn;
  1955.         }
  1956.  
  1957.         hr = S_OK; // Accept E_PENDING.
  1958.  
  1959.         // Wait until the MessageHandler sets an event to tell us the
  1960.         // DPN_MSGID_CONNECT_COMPLETE has been processed.  Then m_hrConnectComplete
  1961.         // will be valid.
  1962.         WaitForSingleObject( m_hConnectCompleteEvent, INFINITE );
  1963.  
  1964.         if( FAILED( m_hrConnectComplete ) )
  1965.         {
  1966.             DXTRACE_ERR_MSGBOX( TEXT("DPN_MSGID_CONNECT_COMPLETE"), m_hrConnectComplete );
  1967.             MessageBox( m_hDlg, TEXT("Unable to join game."),
  1968.                         TEXT("DirectPlay Sample"),
  1969.                         MB_OK | MB_ICONERROR );
  1970.             hr = m_hrConnectComplete;
  1971.         }
  1972.     }
  1973.  
  1974. LCleanReturn:
  1975.     // Cleanup the addresses and memory obtained from GetConnectionSettings
  1976.     
  1977.     if( pSettings )
  1978.     {
  1979.         SAFE_RELEASE( pSettings->pdp8HostAddress );
  1980.         
  1981.         for( DWORD dwIndex=0; dwIndex < pSettings->cNumDeviceAddresses; dwIndex++ )
  1982.             SAFE_RELEASE( pSettings->ppdp8DeviceAddresses[dwIndex] );
  1983.  
  1984.         SAFE_DELETE_ARRAY( pSettings );
  1985.     }
  1986.  
  1987.     return hr;
  1988. }
  1989.  
  1990.  
  1991.  
  1992.  
  1993. //-----------------------------------------------------------------------------
  1994. // Name: LobbyMessageHandler
  1995. // Desc: Handler for DirectPlay messages.  This function is called by
  1996. //       the DirectPlay lobby message handler pool of threads, so be careful of thread
  1997. //       synchronization problems with shared memory
  1998. //-----------------------------------------------------------------------------
  1999. HRESULT WINAPI CNetConnectWizard::LobbyMessageHandler( PVOID pvUserContext,
  2000.                                                        DWORD dwMessageId,
  2001.                                                        PVOID pMsgBuffer )
  2002. {
  2003.     UNREFERENCED_PARAMETER( pvUserContext );
  2004.     HRESULT hr = S_OK;
  2005.  
  2006.     switch(dwMessageId)
  2007.     {
  2008.         case DPL_MSGID_CONNECT:
  2009.         {
  2010.             // This message will be processed when a lobby connection has been
  2011.             // established. If you were lobby launched then
  2012.             // IDirectPlay8LobbiedApplication::Initialize()
  2013.             // waits until this message has been processed before returning, so
  2014.             // take care not to deadlock by making calls that need to be handled by
  2015.             // the thread who called Initialize().  The same is true for WaitForConnection()
  2016.  
  2017.             PDPL_MESSAGE_CONNECT pConnectMsg;
  2018.             pConnectMsg = (PDPL_MESSAGE_CONNECT)pMsgBuffer;
  2019.             PDPL_CONNECTION_SETTINGS pSettings = pConnectMsg->pdplConnectionSettings;
  2020.  
  2021.             m_hLobbyClient = pConnectMsg->hConnectId;
  2022.  
  2023.             if( FAILED( hr = m_pDP->RegisterLobby( m_hLobbyClient, m_pLobbiedApp,
  2024.                                                    DPNLOBBY_REGISTER ) ) )
  2025.                 return DXTRACE_ERR_MSGBOX( TEXT("RegisterLobby"), hr );
  2026.  
  2027.             if( pSettings == NULL )
  2028.             {
  2029.                 // There aren't connection settings from the lobby
  2030.                 m_bHaveConnectionSettingsFromLobby = FALSE;
  2031.             }
  2032.             else
  2033.             {
  2034.                 // Record the player name if found
  2035.                 if( pSettings->pwszPlayerName != NULL )
  2036.                 {
  2037.                     TCHAR strPlayerName[MAX_PATH];
  2038.                     DXUtil_ConvertWideStringToGenericCch( strPlayerName, pSettings->pwszPlayerName, MAX_PATH );
  2039.                     _tcscpy( m_strLocalPlayerName, strPlayerName );
  2040.                 }
  2041.                 else
  2042.                 {
  2043.                     _tcscpy( m_strLocalPlayerName, TEXT("Unknown player name") );
  2044.                 }
  2045.  
  2046.                 m_bHaveConnectionSettingsFromLobby = TRUE;
  2047.             }
  2048.  
  2049.             // Tell everyone we have a lobby connection now
  2050.             SetEvent( m_hLobbyConnectionEvent );
  2051.             break;
  2052.         }
  2053.     }
  2054.  
  2055.     return S_OK;
  2056. }
  2057.  
  2058.  
  2059.  
  2060. //-----------------------------------------------------------------------------
  2061. // Name: StaticLobbyWaitDlgProc()
  2062. // Desc: Static msg handler which passes messages
  2063. //-----------------------------------------------------------------------------
  2064. INT_PTR CALLBACK CNetConnectWizard::StaticLobbyWaitDlgProc( HWND hDlg, UINT uMsg,
  2065.                                                                 WPARAM wParam, LPARAM lParam )
  2066. {
  2067.     if( g_pNCW )
  2068.         return g_pNCW->LobbyWaitDlgProc( hDlg, uMsg, wParam, lParam );
  2069.  
  2070.     return FALSE; // Message not handled
  2071. }
  2072.  
  2073.  
  2074.  
  2075.  
  2076. //-----------------------------------------------------------------------------
  2077. // Name: LobbyWaitDlgProc()
  2078. // Desc: Handles messages for the lobby wait status dialog
  2079. //-----------------------------------------------------------------------------
  2080. INT_PTR CALLBACK CNetConnectWizard::LobbyWaitDlgProc( HWND hDlg, UINT msg,
  2081.                                                       WPARAM wParam, LPARAM lParam )
  2082. {
  2083.     UNREFERENCED_PARAMETER( lParam );
  2084.     switch( msg )
  2085.     {
  2086.         case WM_INITDIALOG:
  2087. #if defined(WIN32_PLATFORM_PSPC) && (_WIN32_WCE >= 300)
  2088.             SHINITDLGINFO   shidi;
  2089.             memset(&shidi, 0, sizeof(SHINITDLGINFO));
  2090.             shidi.dwMask = SHIDIM_FLAGS;
  2091.             shidi.dwFlags = SHIDIF_SIPDOWN | SHIDIF_SIZEDLGFULLSCREEN;
  2092.             shidi.hDlg = hDlg;
  2093.  
  2094.             SetForegroundWindow(hDlg);
  2095.             SHInitDialog(&shidi);
  2096. #endif // WIN32_PLATFORM_PSPC
  2097.  
  2098.             // Set a timer to wait for m_hConnectCompleteEvent to be signaled.
  2099.             // This will tell us when DPN_MSGID_CONNECT_COMPLETE has been processed
  2100.             // which lets us know if the connect was successful or not.
  2101.             SetTimer( hDlg, TIMERID_CONNECT_COMPLETE, 100, NULL );
  2102.  
  2103.             SetDlgItemText( hDlg, IDC_WAIT_TEXT, TEXT("Waiting for lobby connection...") );
  2104.             return TRUE;
  2105.  
  2106.         case WM_COMMAND:
  2107.             switch( LOWORD(wParam) )
  2108.             {
  2109.                 case IDCANCEL:
  2110.                     EndDialog( hDlg, IDCANCEL );
  2111.                     return TRUE;
  2112.             }
  2113.             break;
  2114.  
  2115.         case WM_TIMER:
  2116.         {
  2117.             if( wParam == TIMERID_CONNECT_COMPLETE )
  2118.             {
  2119.                 // Wait for a lobby connection.  If this call
  2120.                 // returns WAIT_OBJECT_0 then the DPL_MSGID_CONNECT will
  2121.                 // have already been processed.
  2122.                 DWORD dwResult = WaitForSingleObject( m_hLobbyConnectionEvent, 100 );
  2123.                 if( dwResult != WAIT_TIMEOUT )
  2124.                     EndDialog( hDlg, IDOK );
  2125.             }
  2126.             break;
  2127.         }
  2128.     }
  2129.  
  2130.     return FALSE; // Didn't handle message
  2131. }
  2132.  
  2133.  
  2134.  
  2135.  
  2136.